﻿using jinmaMesProxy.Excep;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.DataProtection.KeyManagement;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives;
using System.Buffers.Text;
using System.Collections;
using System.Net;
using System.Security.Cryptography;
using System.Security.Cryptography.Xml;
using System.Text;

namespace jinmaMesProxy
{
    public class MyAuthorizationHandler : AuthorizationHandler<IAuthorizationRequirement>
    {
        static Hashtable hashtable;
        static MyAuthorizationHandler()
        {
            hashtable = Hashtable.Synchronized(new Hashtable());
        }
        IHttpContextAccessor httpContextAccessor;
        public MyAuthorizationHandler(IHttpContextAccessor httpContextAccessor)
        {
            this.httpContextAccessor = httpContextAccessor;
        }
        protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, IAuthorizationRequirement requirement)
        {
            var defHttpContext = context.Resource as DefaultHttpContext;
            if (defHttpContext == null || defHttpContext.GetEndpoint() == null)
            {
                context.Succeed(requirement);
                return Task.CompletedTask;
            }
            var _api_key = new StringValues();
            var _iv = new StringValues();
            var querys = defHttpContext.Request.Headers;
            string keyStr = "";
            if (!querys.TryGetValue("apikey", out _api_key) ||
                !querys.TryGetValue("iv", out _iv))
            {
                EndWithFaild("没有提供apikey字段和iv字段");
                return Task.CompletedTask;
            }
            var iv = _iv[0];
            if (iv.Length != 16)
            {
                EndWithFaild("iv必须是16个字");
                return Task.CompletedTask;
            }
            var api_key = _api_key[0];
            try
            {
                keyStr = Decrypt(api_key,iv);//格式是datetime(单位yyyy-mm-dd hh:mm:ss)
            }
            catch (Exception ex)
            {
                Logger.Err(ExceptionUtil.FormatExceptionInfo(ex));
                EndWithFaild("密钥格式错误");
                return Task.CompletedTask;
            }
            DateTime time;
            if (!DateTime.TryParse(keyStr, out time))
            {
                EndWithFaild("不是正确的时间格式");
                return Task.CompletedTask;
            }
            string message = "";
            if (Check(time, iv,out message))
            {
                context.Succeed(requirement);
                return Task.CompletedTask;
            }
            else
            {
                EndWithFaild(message);
                return Task.CompletedTask;
            }
        }
        private void EndWithFaild(string message)
        {
            var result = new ResponseData<string>()
            {
                Data = new string[] { "操作错误" },
                Message = message,
                SystemCode = -1,
                Count = 1
            };
            if (!httpContextAccessor.HttpContext.Response.HasStarted)
            {
                httpContextAccessor.HttpContext.Response.ContentType = "application/json; charset=utf-8";
                httpContextAccessor.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
                httpContextAccessor.HttpContext.Response.WriteAsync(Utils.Serialize(result));
            }
        }
        private bool Check(DateTime datetime, string iv,out string msg)
        {
            msg = "";
            int timeout = int.Parse(ConfigReader.ReadSetting("Sys", "AesExp"));
            if (Math.Abs((DateTime.Now - datetime).TotalSeconds) > timeout)
            {
                msg = "密钥已超时";
                return false;
            }
            List<string> remove = new List<string>();
            foreach (DictionaryEntry item in hashtable)
            {
                if (Math.Abs((DateTime.Now - ((DateTime)item.Value)).TotalSeconds) > timeout)
                    remove.Add(item.Key.ToString());
            }
            foreach (var r in remove)
            {
                hashtable.Remove(r);
            }

            if (!hashtable.ContainsKey(iv))
            {
                hashtable.Add(iv, datetime);
                return true;
            }
            else
            {
                msg = "IV已被使用";
                return false;
            }
        }
        private string Decrypt(string cipherText,string iv)
        {
            using (Aes aes = Aes.Create())
            {
                aes.Key = Encoding.UTF8.GetBytes(ConfigReader.ReadSetting("Sys", "AesKey")); 
                aes.IV = Encoding.UTF8.GetBytes(iv);   
                aes.Mode = CipherMode.CBC;
                using (ICryptoTransform decryptor = aes.CreateDecryptor())
                {
                    var b = Convert.FromBase64String(cipherText);
                    byte[] decrypted = decryptor.TransformFinalBlock(b, 0, b.Length);
                    return Encoding.UTF8.GetString(decrypted);
                }
            }
        }

    }
}
